package com.liurong.quartz.util;

import java.util.Map;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.liurong.quartz.util.entity.JobEntity;
import com.liurong.util.bean.BeanUtil;
import com.liurong.util.redis.RedisTemplate;

/**
 * 修改定时任务状态监听类
 * 
 * @author liurong
 *
 */
public class JobMonitorThread extends Thread {
	private static final Logger logger = LoggerFactory.getLogger(JobMonitorThread.class);
	private RedisTemplate redisTemplate;
	private String ip;
	private Map<String, JobEntity> jobNameMap;

	public JobMonitorThread(Map<String, JobEntity> jobNameMap, RedisTemplate redisTemplate, String ip) {
		this.jobNameMap = jobNameMap;
		this.redisTemplate = redisTemplate;
		this.ip = ip;
	}

	@Override
	public void run() {
		logger.info("jobLisneter启动成功！");

		// 将值设置到redis中
		this.setJobMapToRedis();

		// 开启轮询，监听改变job的请求
		String requestMessage = null;
		String[] requestMessageStr = null;
		String jobBeanName = null;
		String action = null;
		while (!JobStartConfig.isStop) {
			try {
				requestMessage = redisTemplate.rpop(JobMonitorUtil.getJobLqueueStr(ip));
				if (StringUtils.isEmpty(requestMessage)) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						logger.error("线程休眠抛出异常:", e);
					}
					continue;
				}

				logger.info("收到请求  requestMessage={}", requestMessage);
				requestMessageStr = requestMessage.split(":");
				jobBeanName = requestMessageStr[0];
				action = requestMessageStr[1];

				switch (action) {
				case JobMonitorUtil.STOP_ACTION:
					this.stopJob(jobBeanName);
					break;

				case JobMonitorUtil.START_ACTION:
					this.startJob(jobBeanName);
					break;

				case JobMonitorUtil.HAND_START_ACTION:
					this.handStartJob(jobBeanName);
					break;
				case JobMonitorUtil.CHANGE_CRON_ACTION:
					this.changeCronJob(jobBeanName, requestMessageStr[2]);
					break;
				default:
					logger.warn("请求有误！");
				}
			} catch (Exception e) { // 防御性容错
				logger.info("JobMonitorThread error:", e);
			}
		}
	}

	/**
	 * 改变定时任务的cron
	 * 
	 * @param jobBeanName
	 * @param cronStr
	 */
	private void changeCronJob(String jobBeanName, String cronStr) {
		try {
			Scheduler scheduler = JobStartConfig.scheduler;

			JobEntity jobEntity = jobNameMap.get(jobBeanName + ":" + ip);
			String oldTime = jobEntity.getCronStr();

			if (!oldTime.equalsIgnoreCase(cronStr)) { // 触发器
				TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
				// 触发器名,触发器组
				// triggerBuilder.withIdentity(jobName,Scheduler.DEFAULT_GROUP);
				triggerBuilder.startNow(); // 触发器时间设定
				triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cronStr)); // 创建Trigger对象
				CronTrigger trigger = (CronTrigger) triggerBuilder.build();

				TriggerKey triggerKey = new TriggerKey(jobBeanName + ":" + ip, Scheduler.DEFAULT_GROUP);
				scheduler.rescheduleJob(triggerKey, trigger);

				jobEntity.setIsStart(1);
				jobEntity.setCronStr(cronStr);

				this.setJobMapToRedis();
			}
		} catch (SchedulerException e) {
			logger.error("更改执行时间抛出异常", e);
		}
	}

	/**
	 * 手动启动定时任务
	 * 
	 * @param jobBeanName
	 */
	private void handStartJob(String jobBeanName) {
		JobEntity jobEntity = jobNameMap.get(jobBeanName + ":" + ip);
		if (jobEntity == null) {
			logger.info("传入的jobName有误！");
			return;
		}

		if (!jobEntity.isHandStart()) {
			logger.info("该定时任务不支持手动执行！");
			return;
		}

		JobDetailWork bean = (JobDetailWork) BeanUtil.getBean(jobBeanName);
		if (bean == null) {
			System.out.println("传入的jobName有误！");
			return;
		}
		bean.work();
	}

	/**
	 * 开启定时任务
	 * 
	 * @param jobBeanName
	 */
	private void startJob(String jobBeanName) {
		Scheduler scheduler = JobStartConfig.scheduler;
		if (scheduler == null) {
			logger.error("定时任务并没有启动成功！");
		}
		try {
			scheduler.resumeJob(new JobKey(jobBeanName, Scheduler.DEFAULT_GROUP));
		} catch (SchedulerException e) {
			logger.error("开启任务是抛出异常：", e);
			return;
		}

		JobEntity jobEntity = jobNameMap.get(jobBeanName + ":" + ip);
		jobEntity.setIsStart(1);

		this.setJobMapToRedis();
	}

	/**
	 * 暂停定时任务
	 * 
	 * @param jobBeanName
	 */
	private void stopJob(String jobBeanName) {
		Scheduler scheduler = JobStartConfig.scheduler;
		if (scheduler == null) {
			logger.warn("定时任务并没有启动成功！");
			return;
		}
		try {
			scheduler.pauseJob(new JobKey(jobBeanName, Scheduler.DEFAULT_GROUP));
		} catch (SchedulerException e) {
			logger.error("暂停任务是抛出异常：", e);
			return;
		}

		JobEntity jobEntity = jobNameMap.get(jobBeanName + ":" + ip);
		jobEntity.setIsStart(0);

		this.setJobMapToRedis();
	}

	/**
	 * 将map放入redis中
	 */
	private void setJobMapToRedis() {
		String jobNameMapStr = JSON.toJSONString(jobNameMap);
		logger.info("将job内容放入redis中  jobNameMapStr={}", jobNameMapStr);
		StringBuilder key = new StringBuilder();
		key.append("jobNameMapStr");
		key.append(":");
		key.append(ip);
		boolean result = redisTemplate.lock(key.toString(), jobNameMapStr, 1000 * 30, 0);
		logger.info("将job内容放入redis中返回值   result={}", result);
	}
}
